package cn.com.joycode.nimble.opencv.test.javacv;

import cn.com.joycode.nimble.opencv.test.BaseTest;
import lombok.extern.slf4j.Slf4j;
import org.bytedeco.javacpp.indexer.UByteIndexer;
import org.bytedeco.opencv.global.opencv_core;
import org.bytedeco.opencv.global.opencv_highgui;
import org.bytedeco.opencv.global.opencv_imgproc;
import org.bytedeco.opencv.opencv_core.*;
import org.junit.jupiter.api.Test;
import org.opencv.core.CvType;


@Slf4j
public class JavaCvImageProc extends BaseTest {

    /**
     * 通过indexer进行像素操作
     */
    @Test
    public void indexerTest() {
        Mat mat = new Mat(new Size(300, 300), CvType.CV_8UC3);
        Scalar s = new Scalar(0, 0, 255, 0);
        UByteIndexer idx = mat.createIndexer();
        for (int x = 0; x < mat.size().width() - 1; x++) {
            for (int y = 0; y < mat.size().height() - 1; y++) {
                // 绿，红混色得到黄色
                // b 通道
                idx.put(x, y, 0, 0);
                // g 通道
                idx.put(x, y, 1, 255);
                // r 通道
                idx.put(x, y, 2, 255);
            }
        }
        show(mat);
    }

    /**
     * 缩放
     */
    @Test
    public void resizeTest() {
        String resourcePath = "images/douyin/samples/540/0001.png";
        Mat mat = readResource(resourcePath);
        Mat result = new Mat(mat.size().height() / 2, mat.size().width() / 2, CvType.CV_8UC3);
        opencv_imgproc.resize(mat, result, result.size());
        show(result);
    }

    /**
     * 复制
     */
    @Test
    public void copyToTest() {
        String resourcePath = "images/douyin/samples/540/0001.png";
        Mat mat = readResource(resourcePath);
        Mat result = new Mat();
        mat.copyTo(result);
        show(result);
    }

    /**
     * 子矩阵
     */
    @Test
    public void subMat() {
        String resourcePath = "images/douyin/samples/540/0001.png";
        Mat mat = readResource(resourcePath);
        // 通过apply创建子矩阵
        Mat sub = mat.apply(new Rect(100, 100, 300, 300));
        opencv_imgproc.blur(sub, sub, new Size(25, 25));
        // 通过new创建子矩阵
        sub = new Mat(mat, new Rect(100, 500, 300, 300));
        //opencv_imgproc.blur(sub, sub, new Size(5, 25));
        opencv_imgproc.GaussianBlur(sub, sub, new Size(25, 25), 30);
        show(mat);
    }

    /**
     * 灰度化
     */
    @Test
    public void grayScaleTest() {
        String resourcePath = "images/douyin/samples/540/0001.png";
        Mat mat = readResource(resourcePath);
        opencv_imgproc.cvtColor(mat, mat, opencv_imgproc.CV_BGRA2GRAY);
        opencv_core.bitwise_not(mat, mat);
        show(mat);
    }

    /**
     * 反饴
     */
    @Test
    public void bitWiseNotTest() {
        String resourcePath = "images/douyin/samples/540/0001.png";
        Mat mat = readResource(resourcePath);
        opencv_core.bitwise_not(mat, mat);
        show(mat);
    }


    /**
     * 模糊
     */
    @Test
    public void blurTest() {
        String resourcePath = "images/douyin/samples/540/0001.png";
        Mat mat = readResource(resourcePath);
        // 只对子矩阵模糊
        Mat sub = mat.apply(new Rect(100, 100, 300, 300));
        opencv_imgproc.blur(sub, sub, new Size(25, 25));
        show(mat);
    }

    /**
     * 高斯模糊
     */
    @Test
    public void gaussianBlurTest() {
        String resourcePath = "images/douyin/samples/540/0001.png";
        Mat mat = readResource(resourcePath);
        opencv_imgproc.GaussianBlur(mat, mat, new Size(3, 3), 0, 0, 0);
        show(mat);
    }


    /**
     * 边缘检测
     */
    @Test
    public void cannyTest() {
        String resourcePath = "images/douyin/samples/540/0001.png";
        Mat mat = readResource(resourcePath);
        Mat result = new Mat(mat.dims(), mat.size(), mat.type());
        opencv_imgproc.Canny(mat, result, 150.0, 300.0, 3, true);
        show(result);
    }

    /**
     * 掩膜
     */
    @Test
    public void maskTest() {
        String resourcePath = "images/douyin/samples/540/0003.png";
        Mat mat = readResource(resourcePath);
        Mat bg = new Mat();
        mat.copyTo(bg);
        opencv_imgproc.cvtColor(mat, mat, opencv_imgproc.COLOR_BGR2GRAY);
        opencv_imgproc.Canny(mat, mat, 50, 150, 3, true);
        opencv_core.bitwise_not(mat, mat);
        Mat target = new Mat(mat.size().height(), mat.size().width(), CvType.CV_8UC3, new Scalar(0, 0, 255, 0));
        bg.copyTo(target, mat);
        show(target);
    }

    /**
     * 边缘查找
     */
    @Test
    public void findContoursTest() {
        String resourcePath = "images/douyin/samples/540/0003.png";
        Mat mat = readResource(resourcePath);
        Mat target = new Mat(mat.size(), mat.type(), new Scalar(255, 255, 255, 0));
        Mat imageBW = new Mat();
        opencv_imgproc.cvtColor(mat, imageBW, opencv_imgproc.COLOR_BGR2GRAY);
        opencv_imgproc.Canny(imageBW, imageBW, 50, 150, 3, true);
        MatVector contours = new MatVector();
        opencv_imgproc.findContours(imageBW, contours, new Mat(), opencv_imgproc.RETR_LIST, opencv_imgproc.CHAIN_APPROX_SIMPLE);
        long count = contours.size();
        log.info("边缘数据:{}条", count);
        for (int i = 0; i < contours.size(); i++) {
            opencv_imgproc.drawContours(target, contours, i, new Scalar(0, 0, 255, 0), 1, 0, null, 1, null);
        }
        show(target);
    }

    @Test
    public void hConcatTest() {
        String resourcePath = "images/douyin/samples/540/0003.png";
        Mat mat1 = readResource(resourcePath);
        Mat mat2 = new Mat();
        opencv_core.bitwise_not(mat1, mat2);
        Mat result = new Mat();
        opencv_core.hconcat(mat1, mat2, result);
        show(result);
    }

    @Test
    public void vConcatTest() {
        String resourcePath = "images/douyin/samples/540/0003.png";
        Mat mat1 = readResource(resourcePath);
        mat1 = mat1.apply(new Rect(200, 200, 300, 300));
        Mat mat2 = new Mat();
        opencv_core.bitwise_not(mat1, mat2);
        Mat result = new Mat();
        opencv_core.vconcat(mat1, mat2, result);
        show(result);
    }

    /**
     * 颜色映射
     */
    @Test
    public void colorMapTest() {
        String resourcePath = "images/douyin/samples/540/0003.png";
        Mat mat1 = readResource(resourcePath);
        Mat mat2 = new Mat();
        opencv_imgproc.applyColorMap(mat1, mat2, opencv_imgproc.COLORMAP_PINK);
        Mat result = new Mat();
        opencv_core.hconcat(mat1, mat2, result);
        show(result);
    }

    /**
     * 颜色范围查找
     */
    @Test
    public void inRangeTest() {
        String resourcePath = "images/douyin/samples/540/0004.png";
        Mat mat1 = readResource(resourcePath);
        Mat bg = new Mat().put(mat1);
        Mat mat2 = new Mat();
        opencv_imgproc.cvtColor(mat1, mat2, opencv_imgproc.CV_BGR2HSV);
        Mat mask = new Mat();
        // 绿色
        Mat low = new Mat(new Scalar(35, 43, 46, 0));
        Mat high = new Mat(new Scalar(77, 255, 220, 0));
        // 红色
        low = new Mat(new Scalar(0, 43, 46, 0));
        high = new Mat(new Scalar(10, 255, 255, 0));
        opencv_core.inRange(mat2, low, high, mask);
        Mat r = new Mat();
        r.put(mask);
        low = new Mat(new Scalar(156, 0, 100, 0));
        high = new Mat(new Scalar(180, 255, 255, 0));
        opencv_core.inRange(mat2, low, high, mask);
        opencv_core.bitwise_or(r, mask, r);
        mask.put(r);
        log.info("mask type:{}", mask.type());
        Mat m = new Mat();
        mat1.copyTo(m, mask);
        Mat result = new Mat();
        opencv_imgproc.cvtColor(mask, mask, opencv_imgproc.CV_GRAY2BGR);
        MatVector mv = new MatVector();
        mv.put(mat1, m, mask);
        opencv_core.hconcat(mv, result);
        show(result);
    }

    /**
     * 矩阵翻转
     */
    @Test
    public void flipTest() {
        String resourcePath = "images/douyin/samples/540/0003.png";
        Mat mat = readResource(resourcePath);
        Mat mat1 = new Mat(), mat2 = new Mat(), mat3 = new Mat();
        opencv_core.flip(mat, mat1, 0);
        opencv_core.flip(mat, mat2, 1);
        opencv_core.flip(mat, mat3, -1);
        MatVector mv = new MatVector();
        Mat result = new Mat();
        mv.put(mat, mat1, mat2, mat3);
        opencv_core.hconcat(mv, result);
        show(result);
    }

    /**
     * 矩阵旋转
     */
    @Test
    public void rotateTest() {
        String resourcePath = "images/douyin/samples/540/0003.png";
        Mat mat = readResource(resourcePath);
        Mat result = new Mat();
        opencv_core.rotate(mat, result, opencv_core.ROTATE_90_CLOCKWISE);
        show(result);
    }

    /**
     * 图像旋转
     */
    @Test
    public void warpAffineTest() {
        String resourcePath = "images/douyin/samples/540/0003.png";
        Mat mat = readResource(resourcePath);
        Mat result = new Mat();
        Mat rotation_matrix = opencv_imgproc.getRotationMatrix2D(new Point2f(0, 0), 10, 0.5);
        opencv_imgproc.warpAffine(mat, result, rotation_matrix, mat.size());
        show(result);
    }

    /**
     * 滤波
     */
    @Test
    public void filter() {
        String resourcePath = "images/color/balls-red-blue-yellow-green.jpg";
        Mat mat = readResource(resourcePath);
        Mat hsv = new Mat();
        opencv_imgproc.cvtColor(mat, hsv, opencv_imgproc.CV_RGB2HSV);
        Mat low = new Mat(new Scalar(300, 202, 59, 0));
        Mat high = new Mat(new Scalar(360, 255, 255, 0));
        Mat range = new Mat();
        opencv_core.inRange(hsv, low, high, range);
        opencv_imgproc.cvtColor(range, range, opencv_imgproc.CV_GRAY2BGR);
        MatVector mv = new MatVector();
        Mat result = new Mat();
        mv.put(mat, hsv, range);
        opencv_core.vconcat(mv, result);
        show(result);
    }

    @Test
    public void test() {
        String resourcePath = "images/color/balls-red-blue-yellow-green.jpg";
        Mat mat = readResource(resourcePath);
        opencv_highgui.namedWindow("original");
        opencv_highgui.imshow("original", mat);
        opencv_highgui.waitKey();
    }
}

